/*
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2006-2007 Intel Corporation. All Rights Reserved.
//
*/
#include "umc_defs.h"
#if defined (UMC_ENABLE_DV_VIDEO_ENCODER)

#include "umc_dv_enc_dvsd_pal_segment_reader.h"
#include "umc_dv_enc_segment_compressor.h"
#include "umc_dv_enc_block.h"

namespace UMC
{

DVSD_PAL_SegmentReader::DVSD_PAL_SegmentReader(void):
    SegmentReader(12)
{
}

DVSD_PAL_SegmentReader::~DVSD_PAL_SegmentReader(void)
{
}

static
inline
void ReadYLine(Ipp16s *lpBlockYData, Ipp16s LineNum, Ipp8u *lpYSrc)
{
    Ipp16s iX;
    for(iX=0; iX<8; iX++)
        lpBlockYData[iX + LineNum*8] = ((Ipp16s) lpYSrc[iX]) - 128;
}

static
inline
void ReadUVLine(Ipp16s *lpBlockUVData, Ipp16s LineNum, Ipp8u *lpUVSrc)
{
    Ipp16s iX;
    for(iX=0; iX<8; iX++)
        lpBlockUVData[iX +  LineNum*8] =((Ipp16s)lpUVSrc[iX]) - 128;
}

static
void ReadYUV(size_t *YOffsets, size_t *UOffsets, size_t *VOffsets,
             V_SEGMENT *lpVSegment, VideoData *pSrcFrame)
{
    Ipp8u *lpcSrcY, *lpcSrcU, *lpcSrcV;
    Ipp16s LineNum, MBNum;
    BLOCK *Y0, *Y1, *Y2, *Y3, *Cr, *Cb;

    for(MBNum=0; MBNum < 5; MBNum++)
    {
        lpcSrcY = (Ipp8u*)pSrcFrame->GetPlanePointer(0) + YOffsets[MBNum];
        lpcSrcU = (Ipp8u*)pSrcFrame->GetPlanePointer(1) + UOffsets[MBNum];
        lpcSrcV = (Ipp8u*)pSrcFrame->GetPlanePointer(2) + VOffsets[MBNum];

        Y0 = lpVSegment->m_pDCTBlocks + MBNum*6;
        Y1 = Y0 + 1;
        Y2 = Y0 + 2;
        Y3 = Y0 + 3;
        Cr = Y0 + 4;
        Cb = Y0 + 5;

        for (LineNum = 0;LineNum < 8;LineNum++)
        {
            ReadYLine(Y0->m_lpsData, LineNum, lpcSrcY + 8*0);
            ReadYLine(Y1->m_lpsData, LineNum, lpcSrcY + 8*1);
            ReadYLine(Y2->m_lpsData, LineNum, lpcSrcY + 8*0 + pSrcFrame->GetPlanePitch(0)*8);
            ReadYLine(Y3->m_lpsData, LineNum, lpcSrcY + 8*1 + pSrcFrame->GetPlanePitch(0)*8);

            lpcSrcY += pSrcFrame->GetPlanePitch(0);

            ReadUVLine(Cr->m_lpsData, LineNum, lpcSrcV);
            ReadUVLine(Cb->m_lpsData, LineNum, lpcSrcU);

            lpcSrcU += pSrcFrame->GetPlanePitch(1);
            lpcSrcV += pSrcFrame->GetPlanePitch(2);
        }
    }
}

const size_t DVSD_PAL_MBLummaWidth = 16;
const size_t DVSD_PAL_MBLummaHeight = 16;
const size_t DVSD_PAL_MBChromaWidth420 = 8;
const size_t DVSD_PAL_MBChromaHeight420 = 8;

const size_t DVSD_PAL_SBLummaWidth  = DVSD_PAL_MBLummaWidth * 9;
const size_t DVSD_PAL_SBLummaHeight = DVSD_PAL_MBLummaHeight * 3;

const size_t DVSD_PAL_SBChromaWidth420  = DVSD_PAL_MBChromaWidth420 * 9;
const size_t DVSD_PAL_SBChromaHeight420 = DVSD_PAL_MBChromaHeight420 * 3;

static
void InitOffsets(size_t *YOffsets, size_t *UOffsets, size_t *VOffsets,
                 const size_t lPitches[], Ipp16s NumOfDIFSeq, Ipp16s i, Ipp16s k)
{
    //i - DIF sequence order
    //k - order of the video segment in the DIF sequence

    Ipp16s lMBCol, lMBRow;

    lMBCol = k / 3;

    if (lMBCol & 1)
        lMBRow = 2 - (k%3);
    else
        lMBRow = (k%3);

    Ipp32s SBLineShift[5] = {2, 6, 8, 0, 4};
    Ipp32s SBHorzOrder[5] = {2, 1, 3, 0, 4};

    Ipp32s SBNum;
    for(SBNum=0; SBNum < 5; SBNum++)
    {
        YOffsets[SBNum] = (size_t) (
            // destination
            0 +
            // offset of needed SB line
            ((i + SBLineShift[SBNum]) % NumOfDIFSeq) * lPitches[0] * DVSD_PAL_SBLummaHeight +
            // offset of needed SB
            SBHorzOrder[SBNum] * DVSD_PAL_SBLummaWidth +
            // offset of MB in SB
            lMBCol * DVSD_PAL_MBLummaWidth + lMBRow * DVSD_PAL_MBLummaHeight * lPitches[0]);

        UOffsets[SBNum] = (size_t) (
            // destination
            0 +
            // offset of needed SB line
            ((i + SBLineShift[SBNum]) % NumOfDIFSeq) * lPitches[1] * DVSD_PAL_SBChromaHeight420 +
            // offset of needed SB
            SBHorzOrder[SBNum] * DVSD_PAL_SBChromaWidth420 +
            // position MB in SB
            lMBCol * DVSD_PAL_MBChromaWidth420 + lMBRow * DVSD_PAL_MBChromaHeight420 * lPitches[1]);

        VOffsets[SBNum] = (size_t) (
            // destination
            0 +
            // offset of needed SB line
            ((i + SBLineShift[SBNum]) % NumOfDIFSeq) * lPitches[2] * DVSD_PAL_SBChromaHeight420 +
            // offset of needed SB
            SBHorzOrder[SBNum] * DVSD_PAL_SBChromaWidth420  +
            // position MB in SB
            lMBCol * DVSD_PAL_MBChromaWidth420 + lMBRow * DVSD_PAL_MBChromaHeight420 * lPitches[2]);
    }

} //void InitOffsets(...)

void DVSD_PAL_SegmentReader::ReadSegment(V_SEGMENT *lpVSegment, Ipp16s DIFSeqOrder, Ipp16s VSegmentOrder)
{
    size_t YOffsets[5], UOffsets[5], VOffsets[5];
    size_t Pitches[3];
    Pitches[0] = m_lpSourceFrame->GetPlanePitch(0);
    Pitches[1] = m_lpSourceFrame->GetPlanePitch(1);
    Pitches[2] = m_lpSourceFrame->GetPlanePitch(2);

    InitOffsets(YOffsets, UOffsets, VOffsets, Pitches, m_nNumOfDIFSeq, DIFSeqOrder, VSegmentOrder);

    ReadYUV(YOffsets, UOffsets, VOffsets, lpVSegment, m_lpSourceFrame);
}

} //namespace UMC

#endif //(UMC_ENABLE_DV_VIDEO_ENCODER)
